﻿using System;
using System.Drawing;
using System.Net.Sockets;
using System.Text;

/// <summary>
/// Socket连接,双向通信
/// </summary>
public class SocketConnection
{
    #region 构造函数
    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="socket">维护的Socket对象</param>
    /// <param name="server">维护此连接的服务对象</param>
    public SocketConnection(Socket socket, SocketServer server)
    {
        _socket = socket;
        _server = server;
    }

    #endregion

    #region 私有成员

    private readonly Socket _socket;
    private bool _isRec = true;
    private SocketServer _server;
    private bool IsSocketConnected()
    {
        bool part1 = _socket.Poll(1000, SelectMode.SelectRead);
        bool part2 = (_socket.Available == 0);
        if (part1 && part2)
            return false;
        else
            return true;
    }

    #endregion

    #region 外部接口

    /// <summary>
    /// 开始接受客户端消息
    /// </summary>
    public void StartRecMsg()
    {
        try
        {
            byte[] container = new byte[1024 * 1024 * 4];
            _socket.BeginReceive(container, 0, container.Length, SocketFlags.None, asyncResult =>
            {
                try
                {
                    int length = _socket.EndReceive(asyncResult);
                    Property = DateTime.Now.ToString() + " BeginReceive " + Encoding.UTF8.GetString(container);

                    //马上进行下一轮接受，增加吞吐量
                    if (length > 0 && _isRec && IsSocketConnected())
                        StartRecMsg();

                    if (length > 0)
                    {
                        byte[] recBytes = new byte[length];
                        Array.Copy(container, 0, recBytes, 0, length);
                        try
                        {
                            //处理消息
                            if (HandleRecMsg != null)
                            {
                                HandleRecMsg(recBytes, this, _server);
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.ToString());
                        }
                    }
                    else
                        Close();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                    Close();
                }
            }, Property);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
            Close();
        }
    }

    /// <summary>
    /// 发送数据
    /// </summary>
    /// <param name="bytes">数据字节</param>
    public void Send(byte[] bytes)
    {
        try
        {
            _socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, asyncResult =>
            {
                try
                {
                    Property = DateTime.Now.ToString() + "BeginSend" + Encoding.UTF8.GetString(bytes);

                    int length = _socket.EndSend(asyncResult);

                    if (HandleSendMsg != null)
                    {
                        HandleSendMsg(bytes, this, _server);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }, Property);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }

    /// <summary>
    /// 发送字符串（默认使用UTF-8编码）
    /// </summary>
    /// <param name="msgStr">字符串</param>
    public void Send(string msgStr)
    {
        Send(Encoding.UTF8.GetBytes(msgStr));
    }

    /// <summary>
    /// 发送字符串（使用自定义编码）
    /// </summary>
    /// <param name="msgStr">字符串消息</param>
    /// <param name="encoding">使用的编码</param>
    public void Send(string msgStr, Encoding encoding)
    {
        Send(encoding.GetBytes(msgStr));
    }

    /// <summary>
    /// 传入自定义属性
    /// </summary>
    public string Property { get; set; }

    /// <summary>
    /// 关闭当前连接
    /// </summary>
    public void Close()
    {
        try
        {
            _isRec = false;
            _socket.Disconnect(false);
        }
        catch (Exception ex)
        {
            Console.Write(ex.ToString());
        }
        finally
        {
            _server.RemoveConnection(this);
            _socket.Dispose();
            if (HandleClientClose != null)
            {
                HandleClientClose(this, _server);
            }
            GC.Collect();
        }
    }

    #endregion

    #region 事件处理

    /// <summary>
    /// 客户端连接接受新的消息后调用
    /// </summary>
    public Action<byte[], SocketConnection, SocketServer> HandleRecMsg { get; set; }

    /// <summary>
    /// 客户端连接发送消息后回调
    /// </summary>
    public Action<byte[], SocketConnection, SocketServer> HandleSendMsg { get; set; }

    /// <summary>
    /// 客户端连接关闭后回调
    /// </summary>
    public Action<SocketConnection, SocketServer> HandleClientClose { get; set; }

    #endregion
}
